/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (C) 2016-2018, LomboTech Co.Ltd.
 * Author: lomboswer <lomboswer@lombotech.com>
 *
 * memctrl.h - memctrl head file
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#ifndef __MEMCTRL_H__
#define __MEMCTRL_H__

#include <linux/fs.h>

#if defined(CONFIG_ARCH_LOMBO_N7V1)
#include "csp/n7v1/csp_memctrl.h"
#elif defined(CONFIG_ARCH_LOMBO_N7V3)
#include "csp/n7v3/csp_memctrl.h"
#include "csp/n7v3/csp_monitor.h"
#elif defined(CONFIG_ARCH_LOMBO_N7V5)
#include "csp/n7v5/csp_memctrl.h"
#include "csp/n7v5/csp_monitor.h"
#elif defined(CONFIG_ARCH_LOMBO_N7V7)
#include "csp/n7v7/csp_memctrl.h"
#include "csp/n7v7/csp_monitor.h"
#elif defined(CONFIG_ARCH_LOMBO_N5V1)
#include "csp/n5v1/csp_memctrl.h"
#include "csp/n5v1/csp_monitor.h"
#elif defined(CONFIG_ARCH_LOMBO_N9V1)
#include "csp/n9v1/csp_memctrl.h"
#include "csp/n9v1/csp_monitor.h"
#elif defined(CONFIG_ARCH_LOMBO_N9V3)
#include "csp/n9v3/csp_memctrl.h"
#include "csp/n9v3/csp_monitor.h"
#endif

#define COMPATIBLE "lombo,memctrl"

#if defined(CONFIG_ARCH_LOMBO_N7V1)
#define MEMCTRL_NAME "n7v1-memctrl"
#elif defined(CONFIG_ARCH_LOMBO_N7V3)
#define MEMCTRL_NAME "n7v3-memctrl"
#elif defined(CONFIG_ARCH_LOMBO_N7V5)
#define MEMCTRL_NAME "n7v5-memctrl"
#elif defined(CONFIG_ARCH_LOMBO_N7V7)
#define MEMCTRL_NAME "n7v7-memctrl"
#elif defined(CONFIG_ARCH_LOMBO_N5V1)
#define MEMCTRL_NAME "n5v1-memctrl"
#elif defined(CONFIG_ARCH_LOMBO_N9V1)
#define MEMCTRL_NAME "n9v1-memctrl"
#elif defined(CONFIG_ARCH_LOMBO_N9V3)
#define MEMCTRL_NAME "n9v3-memctrl"
#endif

#define LAT_CYCTLES	256
#define CHANNEL_CONF_BIT_MASK	0xc0000000
#define MAX_DRAM_CHANNELS		0x2

/**
 * struct channel_data - master channel data statistic
 * @rd_size: The data size of reading for one channel
 * @wr_size: The data size of writing for one channel
 * @rd_peak: The peak data size of reading for one channel
 * @wr_peak: The peak data size of writing for one channel
 * @rd_num:  The number of reading
 * @wr_num:  The number of writing
 * @rd_latency: Unit: us
 * @wr_latency: Unit: us
 */
struct channel_data {
	u64 rd_size;
	u64 wr_size;
	u64 rd_peak;
	u64 wr_peak;
#if defined(CONFIG_ARCH_LOMBO_N7V5) || defined(CONFIG_ARCH_LOMBO_N5V1) \
	|| defined(CONFIG_ARCH_LOMBO_N7V7)
	u64 rdwr_peak;
#endif
	u64 rd_num;
	u64 wr_num;
	u64 rd_latency;
	u64 wr_latency;
};

/**
 * struct global_data - Global data statistic
 * @total_size: Total Read/Write data size
 * @total_rd_size: Total read data size
 * @total_wr_size: Total write data size
 * @total_rd_peak: Read peak size in total
 * @total_wr_peak: Write peak size in total
 */
struct global_data {
	u64 total_size;
	u32 total_rd_size;
	u32 total_wr_size;
	u32 total_rd_peak;
	u32 total_wr_peak;
#if defined(CONFIG_ARCH_LOMBO_N7V5) || defined(CONFIG_ARCH_LOMBO_N5V1) \
	|| defined(CONFIG_ARCH_LOMBO_N7V7)
	u32 total_rdwr_peak;
#endif
};

/**
 * enum MOP - option of output
 * @OP_CONSOLE: output to console directly
 * @OP_FILE: output to file
 *
 * this option is not work in driver. driver just put result into
 * user space. output to file or console is decided by application
 * (tools/memctrl/memctrl.c)
 */
enum MOP {
	OP_CONSOLE = 0,
	OP_FILE
};

/**
 * enum OVERFLOW - enumerate of overflow status
 * @NO_OVERFLOW: no overflow interuption issue
 * @CYCLE_OVERFLOW: statistic cycle counter overflow
 * @DATA_OVERFLOW: flaw counter overflow
 * @READ_OVERFLOW: read latency counter overflow
 * @WRITE_OVERFLOW: write latency counter overflow
 */
enum OVERFLOW {
	NO_OVERFLOW	= 0x0,
	CYCLE_OVERFLOW	= 0x1,
	DATA_OVERFLOW	= 0x2,
	READ_OVERFLOW	= 0x4,
	WRITE_OVERFLOW	= 0x8
};

/**
 * struct overfolw_info - record overflow interuption status
 * @which: overflow status enumerate by (enum OVERFLOW)
 * @ch_number: channel info
 * @status: record which master latency counter overflow
 *
 * status just for latency overflow
 */
struct overfolw_info {
	u32 which;
	u32 ch_number;
	u32 status;
};

/**
 * struct violation_info - record violation access info
 * @type: access type:write read or read modify write
 * @addr: violation access addr
 * @xpi_id: port number
 * @id: master id number
 */
struct violation_info {
	int type;
	unsigned int addr;
	int xpi_id;
	int id;
};

/**
 * struct monitor_spacen - abstaction a space of space monitor
 * @name: space name
 * @kobj: kobject of space, this will create dir in sysfs
 * @index: space sequence
 * @s_addr: space start address
 * @e_addr: space end address
 * @nw_ip: not write port
 * @node: list node in struct monitor_node
 */
struct monitor_spacen {
	char name[32];
	struct kobject *kobj;
	unsigned int index;
	unsigned int s_addr;
	unsigned int e_addr;
	unsigned int nw_ip:16;
	struct list_head node;
};

/**
 * struct monitor_node - abstaction a monitor
 * @count: count of space
 * @enable: status of monitor enable
 * @update: status of monitor violation access happen
 * @info: record violation access information
 * @entry: list of struct monitor_spacen
 */
struct monitor_node {
	unsigned int count;
	unsigned int enable:1;
	unsigned int update;
	struct violation_info info;
	struct list_head entry;
};

/**
 * struct monitor_master - a master info of monitor
 * @name: master name
 * @xpi_id: master port number
 * @id: master id in port
 * @node: list node of struct monitor:master
 */
struct monitor_master {
	char name[16];
	int xpi_id;
	int id;
	struct list_head node;
};

/**
 * struct monitor - system monitor abstract
 * @parent: parent device handle
 * @kobj: kobject of monitor, this will create dir in sysfs
 * @base: monitor register base addr
 * @global: static globl monitor
 * @space: static space monitor
 * @upadate: work for violation access
 * @ports: port counter in for monitor
 * @master: list of master
 */
struct monitor {
	struct device *parent;
	struct kobject *kobj;
	struct device_node *of_node;
	void __iomem *base;
	struct monitor_node global;
	struct monitor_node space;
	struct work_struct update;
	int ports;
	struct list_head master;
};
typedef struct monitor *mnt_t;

/**
 * struct lombo_memctrl - struct for lombo_mmectrl device
 * @miscdev: lombo_mmectrl is a misc device
 * @reg: reg base for each channels
 * @ch_number: channel number, define how many dram channels been supported yet
 * @irq: irq number for memctrl in linux
 * @sdram_bw_clk: handle of sdram_bw_clk, memctrl work clock
 * @sdram_clk: handle of sdram_clk, for get dram freq info
 * @ddr_bitbase: base of ddr bit reg, for get dram bit width info
 * @sub_arbiter_regbase: for set sub_arbiter priority
 * @lat_div_us: time for a latency(256 cycles of mem_axi_clk)
 * @time: Statistic time, unit:cycles
 * @actual_time: the real statistic time in a specified statistic window
 *		 unit: cycles
 * @lock: spinlock_t for memctrl
 * @period: Dump period, uint:s, useless for now, decided by application
 * @count: Times the program will run, useless for now, decided by application
 * @size_unit: Data size unit: B/KB/MB, for display
 * @flaw_unit: Flaw data unit
 * @sample_unit: Sample unit
 * @op: Output option
 * @log_buf0: result buffer 0
 * @log_offset0: offset of log_buf0
 * @log_buf1: result buffer 1
 * @log_offset1: offset of log_buf1
 * @file: File path, useless for now, decided by application
 * @pfile: FIle handle, useless for now, decided by application
 * @fpos: file offset, useless for now, decided by application
 * @running: Is program runding
 * @overflow: info of statistic if overflow irq
 * @mnt: monitor for memory violation access
 * @data_unit_array: handle of data_units array
 * @flaw_unit_array: handle of flaw_units array
 * @sample_unit_array: handle of sample_units array
 * @channel_info_array: handle of channel_info array
 * @master_prio_array: handle of master_info array
 */
struct lombo_memctrl {
	struct miscdevice miscdev;

	void __iomem *reg[MAX_DRAM_CHANNELS];
	int ch_number;
	int irq;

	struct clk *sdram_bw_clk;
	struct clk *sdram_clk;
	void __iomem *ddr_bitbase[MAX_DRAM_CHANNELS];
	void __iomem *noc;
	void *sub_arbiter_regbase;
	int lat_div_us;
	u32 time;
	u32 actual_time[MAX_DRAM_CHANNELS];
	spinlock_t lock;
	u32 period;
	u32 count;
	u32 size_unit;
	u32 flaw_unit;
	u32 sample_unit;
	enum MOP op;
	char *log_buf0;
	u32 log_offset0;
	char *log_buf1;
	u32 log_offset1;
	char file[128];
	struct file *pfile;
	loff_t fpos;
	bool running;
	struct overfolw_info overflow;
	mnt_t mnt[MAX_DRAM_CHANNELS];

	const struct data_unit_array *data_unit_array;
	const struct flaw_unit_array *flaw_unit_array;
	const struct sample_unit_array *sample_unit_array;
	const struct channel_info_array *channel_info_array;
	const struct master_prio_array *master_prio_array;
};

void __iomem *lombo_get_noc_addr(void);
void __iomem *lombo_get_sarb_addr(void);

#ifdef CONFIG_ARCH_LOMBO_N7V1
static inline int mnt_setup(struct device *dev) { return 0; }
static inline int mnt_destroy(struct device *dev) { return 0; }
static inline int check_global_monitor(mnt_t mnt) { return 0; }
static inline int check_space_monitor(mnt_t mnt) { return 0; }
#else
extern int mnt_setup(struct device *dev);
extern int mnt_destroy(struct device *dev);
extern int check_global_monitor(mnt_t mnt);
extern int check_space_monitor(mnt_t mnt);
#endif

#endif /* __MEMCTRL_H__ */
